package com.mrzhou.core.tool.launch;

import com.mrzhou.core.tool.constants.NacosConstant;
import com.mrzhou.core.tool.utils.ClassUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 在SpringApplication启动前增加一些项目中通用的启动参数
 * @author qiang.zhou
 */
public class CloudApplication {

    private static final Logger log = LoggerFactory.getLogger(CloudApplication.class);

    public static ConfigurableApplicationContext run(String appName, Class source, String... args) {
        SpringApplicationBuilder builder = createSpringApplicationBuilder(appName, source, args);
        return builder.run(args);
    }

    public static SpringApplicationBuilder createSpringApplicationBuilder(String appName, Class source, String... args) {
        // 应用名称一定不能为空
        Assert.hasText(appName, "项目的应用名称不能为空！");
        // SpringBoot环境抽象, StandardEnvironment正常的环境, StandardServletEnvironment web环境
        ConfigurableEnvironment environment = new StandardEnvironment();
        // 获取当前系统配置(systemProperties) 及系统环境(systemEnvironment)
        MutablePropertySources sources = environment.getPropertySources();
        sources.addFirst(new SimpleCommandLinePropertySource(args));
        // 获取当前项目运行的环境变量
        String[] activeProfiles = environment.getActiveProfiles();
       // 设置默认的SpringBoot启动环境
        SpringApplicationBuilder builder = new SpringApplicationBuilder(new Class[]{source});
        String profile ;
        if(activeProfiles.length <= 0) {
            profile = "dev";
            builder.profiles(profile);
        } else {
            // 检查是否包含多种不同环境
            if(activeProfiles.length != 1) {
                throw new RuntimeException("同时存在环境变量:[" + StringUtils.arrayToCommaDelimitedString(activeProfiles) + "]");
            }
            profile = activeProfiles[0];
        }

        // 获取当前jar的启动位置
        String startJarPath = CloudApplication.class.getResource("/").getPath().split("!")[0];
        log.info("----启动中，读取到的环境变量:[{}]，jar地址:[{}]----", profile, startJarPath);
        Properties props = System.getProperties();
        props.setProperty("spring.application.name", appName);
        props.setProperty("spring.profiles.active", profile);
        // 是否允许SpringBean重载
        props.setProperty("spring.main.allow-bean-definition-overriding", "true");
        // 设置链路追踪的采样率
        props.setProperty("spring.sleuth.sampler.rate", "1");
        props.setProperty("spring.cloud.nacos.config.group", "DEFAULT_GROUP");
        props.setProperty("spring.cloud.nacos.config.prefix", "cloud");
        // 设置应用需要从Nacos中读取的配置文件
        NacosConstant.setSharedDataIds(props, profile);
//        props.setProperty("spring.cloud.nacos.config.shared-dataids", NacosConstant.sharedDataIds(profile)); // 本配置以过时, 采用之前配置
        // 设置配置文件的格式
        props.setProperty("spring.cloud.nacos.config.file-extension", "yaml");
        List<LaunchService> launchList = getLaunchList();
        launchList.stream().sorted(Comparator.comparing(LaunchService::getOrder)).collect(Collectors.toList()).forEach((launchService -> {
            launchService.launcher(builder, appName, profile, isLocalDev());
        }));
        return builder;
    }

    public static boolean isLocalDev() {
        String osName = System.getProperty("os.name");
        return StringUtils.hasText(osName) && !"LINUX".equalsIgnoreCase(osName);
    }

    /**
     * 获取cloud-common模块下com.mrzhou.common下扩展参数设置
     */
    private static List<LaunchService> getLaunchList() {
        List<LaunchService> launchServiceList = new ArrayList<>();
        ClassUtil.getClasses("com.mrzhou.common").forEach(clazz -> {
                if(ClassUtil.isClass(clazz)) {
                    Stream.of(clazz.getInterfaces()).forEach(var -> {
                        if(var.getName().equals(LaunchService.class.getName())) {
                            try {
                                launchServiceList.add((LaunchService) newInstance(clazz));
                            } catch (Exception e) {}
                        }
                    });
                }
        });
        return launchServiceList;
    }

    private static Object newInstance(Class<?> clazz) {
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            return null;
        }
    }


}
